package websocket

import (
	"encoding/json"
	"fmt"

	"github.com/gorilla/websocket"

	"sync"
)

type Client struct {
	ID string

	Socket *websocket.Conn

	Send chan []byte
}

type ClientManager struct {
	// 所有连接的客户端
	Clients map[*Client]bool
	//Web side MESSAGE we use Broadcast to receive, and finally distribute it to all clients
	broadcast chan []byte
	//Newly created long connection client
	Register chan *Client
	//Newly canceled long connection client
	Unregister chan *Client

	// map
	ClientMap map[string]*Client

	// map
	Controller func(client *Client, content *Content)
}

// 接收消息载体
type Content struct {
	Token   string  `json:"token"`
	Action  string  `json:"action"`
	Payload Payload `json:"payload"`
}

type ResponseContent struct {
	Action  string `json:"action"`
	Payload string `json:"payload"`
}

type Payload struct {
	Type    int    `json:"type"`
	Content string `json:"content"`
	Target  string `json:"target"`
}

type MessageType int

const TextMessage MessageType = 1

const BinaryMessage MessageType = 2

const CloseMessage MessageType = 3

const ConnectMessage MessageType = 4

const PingMessage MessageType = 5

const PongMessage MessageType = 6

type Message struct {
	Sender    string      `json:"sender,omitempty"`    //发送者
	Recipient string      `json:"recipient,omitempty"` //接收者
	Content   string      `json:"content,omitempty"`   //内容
	Type      MessageType `json:"type,omitempty"`      //类型
	Owner     bool        `json:"owner"`               //是否是发送者
}

// once 确保全局的 Manager 对象只实例一次
var once sync.Once

var Manager *ClientManager

func NewClientManager() *ClientManager {
	once.Do(func() {
		Manager = &ClientManager{
			broadcast:  make(chan []byte),
			Register:   make(chan *Client),
			Unregister: make(chan *Client),
			Clients:    make(map[*Client]bool),
			ClientMap:  make(map[string]*Client),
			Controller: func(client *Client, content *Content) {},
		}
	})

	return Manager
}

func (manager *ClientManager) RegisterController(controller func(client *Client, content *Content)) {
	manager.Controller = controller
}

func (manager *ClientManager) Start() {

	for {
		select {
		//If there is a new connection access, pass the connection to conn through the channel
		case conn := <-manager.Register:
			//Set the client connection to true
			manager.Clients[conn] = true
			manager.ClientMap[conn.ID] = conn
			//Format the message of returning to the successful connection JSON
			manager.Broadcast("A new socket has connected. ", ConnectMessage, conn)
			//If the connection is disconnected
		case conn := <-manager.Unregister:
			//Determine the state of the connection, if it is true, turn off Send and delete the value of connecting client
			if _, ok := manager.Clients[conn]; ok {
				close(conn.Send)
				delete(manager.Clients, conn)
				delete(manager.ClientMap, conn.ID)
				manager.Broadcast("A socket has disconnected. ", CloseMessage, conn)
			}
			//broadcast
			// case message := <-manager.broadcast:
			//Traversing the client that has been connected, send the message to them
			// for conn := range manager.Clients {
			// 	select {
			// 	case conn.Send <- message:
			// 	default:
			// 		close(conn.Send)
			// 		delete(manager.Clients, conn)
			// 		delete(manager.ClientMap, conn.ID)
			// 	}
			// }
		}
	}
}

func (manager *ClientManager) Connect(id string, socket *websocket.Conn) {
	client := &Client{ID: id, Socket: socket, Send: make(chan []byte)}
	manager.Register <- client

	go client.Read()
	go client.Write()
}

// Define the send method of client management
func (manager *ClientManager) Broadcast(Content string, Type MessageType, Ignore *Client) {

	for conn := range manager.Clients {
		//Send messages not to the shielded connection
		if conn != Ignore {
			conn.Send <- []byte(Content)
		}
	}
}

// Define the read method of the client structure
func (c *Client) Read() {
	defer func() {
		Manager.Unregister <- c
		_ = c.Socket.Close()
	}()

	for {
		//Read message
		_, message, err := c.Socket.ReadMessage()
		//If there is an error message, cancel this connection and then close it
		if err != nil {
			Manager.Unregister <- c
			_ = c.Socket.Close()
			break
		}

		var content Content

		fmt.Println("ffffffff", string(message))

		json.Unmarshal(message, &content)

		NewClientManager().Controller(c, &content)

		// if content.Action == "ping" {

		// 	payload := Payload{
		// 		Type:    1,
		// 		Message: "pong",
		// 		Target:  "",
		// 	}

		// 	str, _ := json.Marshal(payload)

		// 	content.Action = "pong"
		// 	content.Payload = string(str)

		// 	data, _ := json.Marshal(content)
		// 	c.Send <- data
		// }

		//If there is no error message, put the information in Broadcast
		// jsonMessage, _ := json.Marshal(&Message{Type: TextMessage, Sender: c.ID, Content: string(message)})
		// Manager.broadcast <- jsonMessage
	}
}

// Write 方法用于将消息写入 WebSocket 连接并发送到 Web 端。
// 在方法结束时，会关闭 WebSocket 连接。
func (c *Client) Write() {
	// 在函数结束时关闭 WebSocket 连接
	defer func() {
		_ = c.Socket.Close()
	}()

	for {
		select {
		//Read the message from send
		case message, ok := <-c.Send:
			//If there is no message
			if !ok {
				_ = c.Socket.WriteMessage(websocket.CloseMessage, []byte{})
				return
			}
			//Write it if there is news and send it to the web side
			_ = c.Socket.WriteMessage(websocket.TextMessage, message)
		}
	}
}

// SendTo 方法用于发送消息到指定的接收者。
//
// 参数：
// to: 接收者的标识符。
// message: 要发送的消息内容。
// t: 消息的类型。
//
// 该方法首先将消息封装成一个 JSON 格式的字符串，然后通过客户端的 Send 通道发送出去。
func (c *Client) SendTo(to *Client, message string, t MessageType, owner bool) {
	// m := &Message{
	// 	Type:      t,
	// 	Sender:    c.ID,
	// 	Recipient: to.ID,
	// 	Content:   message,
	// 	Owner:     false,
	// }

	// 将消息封装成 JSON 格式的字符串。
	// toMessage, _ := json.Marshal(m)
	// 通过客户端的 Send 通道发送消息。
	to.Send <- []byte(message)

	// if owner {
	// 	if owner {
	// 		m.Owner = true
	// 	}
	// 	// 将消息封装成 JSON 格式的字符串。
	// 	fromMessage, _ := json.Marshal(m)
	// 	c.Send <- []byte(fromMessage)
	// }
}
